#include <measureTask.h>
#include <colorMixingTask.h>
#include <ledParamTables.h>

#define ADC_SAMPLING_NUM        2
#define ADC_SAMPLING_NUM_POS    1

typedef struct{
  int16_t  result;
  uint16_t valid;
}vLedVolt_t;

typedef struct{
  uint16_t    vbatVolt;
  int16_t     vTemperature;//0.1C
  vLedVolt_t  vLedVolt[3];
}AdcResult_t;


int16_t ledPNVoltAt25C[3] = 
{ //30mA @ 25C
  [LED_RED]   = 1920,//2172,
  [LED_GREEN] = 3032,//3331,
  [LED_BLUE]  = 2810,//2950
};

MeasureParam_t MeasureParam;
uint16_t adcValueSum     = 0;
uint16_t samplingCount   = 0;
uint16_t vBGvolt;
AdcResult_t adcResult;
TaskState_t adcTaskState = TASK_STATE_INIT;
AdcMeasureItem_t adcItem = ADC_MEASURE_ITEM_NONE;

void MeasureTimerExpired(SoftTimer_t *timer);

SoftTimer_t measureTimer = {
    .mode     = TIMER_ONE_SHOT_MODE,
    .interval = 100,
    .handler  = MeasureTimerExpired
};

void MeasureTimerExpired(SoftTimer_t *timer)
{
    TM_PostTask(TASK_ID_ADC);
}

void ADCMeasureResult_ISR(AdcMeasureItem_t item, uint16_t value)
{
    adcValueSum += value;
    samplingCount ++;
    TM_PostTask(TASK_ID_ADC);
}

void adcMeasureQueueStart(void)
{
//    uint16_t pwm[3];
//    int32_t volt;
//    bool syncEnable = true;
  
//    switch(adcItem)
//    {
  //    case ADC_MEASURE_ITEM_NONE:
  //      adcValueSum = 0;
  //      samplingCount = 0;
  //      adcItem = ADC_MEASURE_ITEM_VBAT;
  //      break;
  
  //    case ADC_MEASURE_ITEM_VBAT:
  //      if (samplingCount >= ADC_SAMPLING_NUM){
  //          volt = ((uint32_t)adcValueSum*vBGvolt) >> (12 - 4 + ADC_SAMPLING_NUM_POS);//4096/16/8
  //          if(adcResult.vbatVolt == INVALID_PARAM){
  //              adcResult.vbatVolt = volt;
  //          }else{
  //              adcResult.vbatVolt = (volt + (uint32_t)adcResult.vbatVolt*7) >> 3;
  //          }
  //          adcValueSum = 0;
  //          samplingCount = 0;
  //          adcItem = ADC_MEASURE_ITEM_VTEMP;
  //      }
  //      break;
  
  //    case ADC_MEASURE_ITEM_VTEMP:
  //      if (samplingCount >= ADC_SAMPLING_NUM){
  //          volt = ((uint32_t)adcValueSum*vBGvolt) >> (12 + ADC_SAMPLING_NUM_POS);//4096/16/8
  //          volt = (int32_t)volt*1647/204 - 2673 - 250;
  //          if(adcResult.vTemperature == INVALID_PARAM){
  //              adcResult.vTemperature = volt;
  //          }else{
  //              adcResult.vTemperature = (adcResult.vTemperature*7 + volt)/8;
  //          }
  //          adcItem = ADC_MEASURE_ITEM_VBAT;
  //          if (CLM_FadingIsFinished() == true){
  //              CLM_GetCurrentPWMs(&pwm[CHANNEL_RED], &pwm[CHANNEL_GREEN], &pwm[CHANNEL_BLUE]);
  //              if (pwm[0] >= PN_VOLT_DETECT_START_DUTY){
  //                  if (pwm[0] == 65535){
  //                      syncEnable = false;
  //                  }
  //                  adcItem = ADC_MEASURE_ITEM_VLED0;
  //              }else if (pwm[1] >= PN_VOLT_DETECT_START_DUTY){
  //                  adcItem = ADC_MEASURE_ITEM_VLED1;
  //                  if (pwm[1] == 65535){
  //                      syncEnable = false;
  //                  }
  //              }else if (pwm[2] >= PN_VOLT_DETECT_START_DUTY){
  //                  adcItem = ADC_MEASURE_ITEM_VLED2;
  //                  if (pwm[2] == 65535){
  //                      syncEnable = false;
  //                  }
  //              }
  //          }
  //          adcValueSum = 0;
  //          samplingCount = 0;
  //      }
  //      break;
  
  //    case ADC_MEASURE_ITEM_VLED0:
  //      if (samplingCount >= ADC_SAMPLING_NUM){
  //          volt = (uint32_t)(((uint64_t)MeasureParam.LedPN[0].coefficient * adcValueSum >> ADC_SAMPLING_NUM_POS) + MeasureParam.LedPN[0].offset) >> LED_PN_GAIN_POS;
  //          if( adcResult.vLedVolt[0].result ==  INVALID_PARAM){
  //              adcResult.vLedVolt[0].result = volt;
  //          }else{
  //              adcResult.vLedVolt[0].result = (adcResult.vLedVolt[0].result*7 + (uint32_t)volt) >> 3;
  //          }
  //          adcResult.vLedVolt[0].valid = true;
  //          adcItem = ADC_MEASURE_ITEM_VBAT;
  //          if (CLM_FadingIsFinished() == true){
  //              CLM_GetCurrentPWMs(&pwm[CHANNEL_RED], &pwm[CHANNEL_GREEN], &pwm[CHANNEL_BLUE]);
  //              if (pwm[1] >= PN_VOLT_DETECT_START_DUTY){
  //                  adcItem = ADC_MEASURE_ITEM_VLED1;
  //                  if (pwm[1] == 65535){
  //                      syncEnable = false;
  //                  }
  //              }else if (pwm[2] >= PN_VOLT_DETECT_START_DUTY){
  //                  adcItem = ADC_MEASURE_ITEM_VLED2;
  //                  if (pwm[2] == 65535){
  //                      syncEnable = false;
  //                  }
  //              }
  //          }
  //          adcValueSum = 0;
  //          samplingCount = 0;
  //      }
  //      break;
  
  //    case ADC_MEASURE_ITEM_VLED1:
  //      if (samplingCount >= ADC_SAMPLING_NUM){
  //          volt = (uint32_t)(((uint64_t)MeasureParam.LedPN[1].coefficient * adcValueSum >> ADC_SAMPLING_NUM_POS) + MeasureParam.LedPN[1].offset) >> LED_PN_GAIN_POS;
  //          if (adcResult.vLedVolt[1].result == INVALID_PARAM){
  //              adcResult.vLedVolt[1].result = volt;
  //          }else{
  //              adcResult.vLedVolt[1].result =  (adcResult.vLedVolt[1].result*7 + (uint32_t)volt) >> 3;
  //          }
  //          adcResult.vLedVolt[1].valid = true;
  //          adcItem = ADC_MEASURE_ITEM_VBAT;
  //          if (CLM_FadingIsFinished() == true){
  //              CLM_GetCurrentPWMs(&pwm[CHANNEL_RED], &pwm[CHANNEL_GREEN], &pwm[CHANNEL_BLUE]);
  //              if (pwm[2] >= PN_VOLT_DETECT_START_DUTY){
  //                  adcItem = ADC_MEASURE_ITEM_VLED2;
  //                  if (pwm[2] == 65535){
  //                      syncEnable = false;
  //                  }
  //              }
  //          }
  //          adcValueSum = 0;
  //          samplingCount = 0;
  //      }
  //      break;
  
  //    case ADC_MEASURE_ITEM_VLED2:
  //      if (samplingCount >= ADC_SAMPLING_NUM){
  //          volt = (uint32_t)(((uint64_t)MeasureParam.LedPN[2].coefficient * adcValueSum >> ADC_SAMPLING_NUM_POS) + MeasureParam.LedPN[2].offset) >> LED_PN_GAIN_POS;
  //          if (adcResult.vLedVolt[2].result == INVALID_PARAM){
  //              adcResult.vLedVolt[2].result = volt;
  //          }else{
  //              adcResult.vLedVolt[2].result =  (adcResult.vLedVolt[2].result*7 + (uint32_t)volt) >> 3;
  //          }
  //          adcResult.vLedVolt[2].valid = true;
  ////          DEBUG_OUT("VBAT: %d, VEMP:%d, Red:%3d,Green:%3d,Blue:%3d \r\n",adcResult.vbatVolt,adcResult.vTemperature, adcResult.vLedVolt[2].result,adcResult.vLedVolt[0].result,adcResult.vLedVolt[1].result);
  //          adcItem = ADC_MEASURE_ITEM_VBAT;
  //          adcValueSum = 0;
  //          samplingCount = 0;
  //      }
  //      break;
  
  //    default:
  //      adcItem = ADC_MEASURE_ITEM_NONE;
  //      break;
//    }
//    if (adcItem != ADC_MEASURE_ITEM_NONE){
//        ADC_Init(adcItem,syncEnable);
//        ADC_RegisterIRQ(ADCMeasureResult_ISR);
//        ADC_Start();
//    }
}


int16_t ADC_GetVBatVolt(void)
{
    return adcResult.vbatVolt;
}

/*
125(486.8mV)    25(362.3mV)   -40(282.2mV)
*/ 

int16_t ADC_GetChipTemperature(void)
{
    return adcResult.vTemperature;
}


int16_t getTemperature(TempCompensation_t const *table,int16_t deltaPNVolt)
{
    int16_t temperature;
    uint8_t index = 0;
    for (index = 0; index < TEMP_CMP_NUM_MAX; index++){
        if (deltaPNVolt >= table[index].deltaVoltPN){
            break;
        }
    }
    if (index == 0){
        temperature = table[0].temperature;
    }else if(index >= TEMP_CMP_NUM_MAX){
        temperature = table[TEMP_CMP_NUM_MAX -1].temperature;
    }else{
        temperature = table[index-1].temperature;
        temperature+=(int32_t)(deltaPNVolt - table[index-1].deltaVoltPN)*(table[index].temperature - table[index-1].temperature)/(table[index].deltaVoltPN - table[index-1].deltaVoltPN);
    }
    return temperature;
}


int16_t ADC_GetLedTemperature(LedNumber_t ledNo)
{
    int16_t ledTemperature;
    int16_t temperature[3]= {0x7FFF,0x7FFF, 0x7FFF};
    int16_t deltaV[3];
    int16_t temp = 0;
    int8_t count = 0;
    if (adcResult.vLedVolt[LED_RED].valid){
        deltaV[LED_RED] = adcResult.vLedVolt[LED_RED].result - ledPNVoltAt25C[LED_RED];
        temperature[LED_RED] = getTemperature(TABLE_CMP_INTENSITY_RED,deltaV[LED_RED]);
        temp +=temperature[LED_RED];
//        DEBUG_OUT("VRED: %d ",temperature[LED_RED]);
        count++;
    }
    if (adcResult.vLedVolt[LED_GREEN].valid){
        deltaV[LED_GREEN] = adcResult.vLedVolt[LED_GREEN].result - ledPNVoltAt25C[LED_GREEN];
        temperature[LED_GREEN] = getTemperature(TABLE_CMP_INTENSITY_RED,deltaV[LED_GREEN]);
        temp +=temperature[LED_GREEN];
//        DEBUG_OUT("VGREEN: %d ",temperature[LED_GREEN]);
        count++;
    }
    if (adcResult.vLedVolt[LED_BLUE].valid){
        deltaV[LED_BLUE] = adcResult.vLedVolt[LED_BLUE].result - ledPNVoltAt25C[LED_BLUE];
        temperature[LED_BLUE] = getTemperature(TABLE_CMP_INTENSITY_RED,deltaV[LED_BLUE]);
        temp +=temperature[LED_BLUE];
//        DEBUG_OUT("VBLUE: %d ",temperature[LED_BLUE]);
        count++;
    }
    
    if (count){
        ledTemperature = temp/count;
    }
    return ledTemperature;
}

void LedPNParam_Init(void)
{
//    int32_t realDeltaV0; 
//    int32_t realDeltaV1;
//    int32_t measDeltaV0;
//    int32_t measDeltaV1;
//    
//    int32_t tSensor25C;
//    int32_t tSensor125C;
//    
//    adcResult.vbatVolt     = INVALID_PARAM;
//    adcResult.vTemperature = INVALID_PARAM;
//    adcResult.vLedVolt[0].result = INVALID_PARAM;
//    adcResult.vLedVolt[1].result = INVALID_PARAM;
//    adcResult.vLedVolt[2].result = INVALID_PARAM;
//    adcResult.vLedVolt[0].valid = false;
//    adcResult.vLedVolt[1].valid = false;
//    adcResult.vLedVolt[2].valid = false;
//    
//    vBGvolt = HWCFG_SFRS->BANDGAP_VOLT;
//    /****************************************************************************/
//    //CH0
//    realDeltaV0 = HWCFG_SFRS->LED0_PN.deltaV0_input;
//    realDeltaV1 = HWCFG_SFRS->LED0_PN.deltaV1_input;
//    measDeltaV0 = HWCFG_SFRS->LED0_PN.deltaV0_output;
//    measDeltaV1 = HWCFG_SFRS->LED0_PN.deltaV1_output;
//    
//    MeasureParam.LedPN[0].coefficient = (realDeltaV1 - realDeltaV0)*LED_PN_GAIN/(measDeltaV1 - measDeltaV0);
//    MeasureParam.LedPN[0].offset      = realDeltaV0*LED_PN_GAIN - MeasureParam.LedPN[0].coefficient*measDeltaV0;
//    /****************************************************************************/
//    //CH1
//    realDeltaV0 = HWCFG_SFRS->LED1_PN.deltaV0_input;
//    realDeltaV1 = HWCFG_SFRS->LED1_PN.deltaV1_input;
//    measDeltaV0 = HWCFG_SFRS->LED1_PN.deltaV0_output;
//    measDeltaV1 = HWCFG_SFRS->LED1_PN.deltaV1_output;
//    
//    MeasureParam.LedPN[1].coefficient = (realDeltaV1 - realDeltaV0)*LED_PN_GAIN/(measDeltaV1 - measDeltaV0);
//    MeasureParam.LedPN[1].offset      = realDeltaV0*LED_PN_GAIN - MeasureParam.LedPN[1].coefficient*measDeltaV0;
//    /****************************************************************************/
//    //CH2
//    realDeltaV0 = HWCFG_SFRS->LED2_PN.deltaV0_input;
//    realDeltaV1 = HWCFG_SFRS->LED2_PN.deltaV1_input;
//    measDeltaV0 = HWCFG_SFRS->LED2_PN.deltaV0_output; //315
//    measDeltaV1 = HWCFG_SFRS->LED2_PN.deltaV1_output; //841
//    
//    MeasureParam.LedPN[2].coefficient = (realDeltaV1 - realDeltaV0)*LED_PN_GAIN/(measDeltaV1 - measDeltaV0);
//    MeasureParam.LedPN[2].offset      = realDeltaV0*LED_PN_GAIN - MeasureParam.LedPN[2].coefficient*measDeltaV0; 
//    /****************************************************************************/
//    //Tsensor
//    tSensor25C  = HWCFG_SFRS->TSENSOR_CODE_25C;
//    tSensor125C = HWCFG_SFRS->TSENSOR_CODE_125C;
//    MeasureParam.Temp.coefficient = (1250 - 250)*LED_PN_GAIN/(tSensor125C - tSensor25C);
//    MeasureParam.Temp.offset      = 250*LED_PN_GAIN - MeasureParam.Temp.coefficient * tSensor25C;
}


void ADC_TaskHandler(void)
{
    switch(adcTaskState){
    case TASK_STATE_INIT:               //初始化部分只执行一次
      LedPNParam_Init();
      SoftTimer_Start(&measureTimer);   //用于单次定时后再次调用，进入ACTIVE阶段
      adcTaskState = TASK_STATE_ACTIVE;
      adcItem = ADC_MEASURE_ITEM_NONE;  //选择要测量的部分
      break;
    case TASK_STATE_ACTIVE:
      adcMeasureQueueStart();
      break;
    }
}


